class Token {
    // 注册几个Token类型
    static INVALID_TOKEN_TYPE =  0;
    static PLUS = 1;
    static MULT = 2;
    static DOT = 3;
    static INT = 4;
    static VEC = 5
    static ID = 6;
    static ASSIGN = 7;
    static PRINT = 8;
    static STAT_LIST = 9; 
    type : number;
    text:string 

    constructor(type:number,text:string = ""){
        this.type = type;
        this.text = text;
    }

    toString(){
        return this.text
    }
}
/**
 * AST抽象类
 */
class HeteroAST {
    token:Token | null;
    constructor(t:Token | null = null){
        this.token = t;
    }
    toString(){
        return this.token?.toString()
    }
    toStringTree(){
        return this.toString();
    }
}

abstract class VecMathNode extends HeteroAST{
    constructor(token:Token | null){
        super(token)
    }

    print(){
        process.stdout.write(this.token ? this.token.toString() : "<null>");
    }
}
/**
 * 具体实现语法节点
 */
class ExprNode extends VecMathNode{
    constructor(t:Token | null = null){
        super(t)
    }
}

class StatNode extends VecMathNode{

}

class StatListNode extends VecMathNode {
    elements:StatNode[] = [];
    constructor(elements:StatNode[]){
        super(new Token(Token.STAT_LIST));
        this.elements = elements
    }
    print(){
        this.elements.forEach(e => e.print())
    }
}
class IntNode extends ExprNode {
    constructor(t:Token){
        super(t)
    }
}

class VarNode extends ExprNode {

}


class AddNode extends ExprNode{
    left:ExprNode;
    right:ExprNode;

    constructor(left:ExprNode,addToken:Token,right:ExprNode){
        super(addToken);
        this.left = left;
        this.right = right;
    }

    print(){
        this.left.print();
        process.stdout.write("+");
        this.right.print()
    }
}
class MultNode extends ExprNode {
    left:ExprNode;
    right:ExprNode;

    constructor(left:ExprNode,addToken:Token,right:ExprNode){
        super(addToken);
        this.left = left;
        this.right = right;
    }

    print(){
        this.left.print();
        process.stdout.write("*");
        this.right.print()
    }
}
class DotProduct extends ExprNode {
    left:ExprNode;
    right:ExprNode;

    constructor(left:ExprNode,addToken:Token,right:ExprNode){
        super(addToken);
        this.left = left;
        this.right = right;
    }

    print(){
        this.left.print();
        process.stdout.write(".");
        this.right.print()
    }
}

class VectorNode extends ExprNode {
    elements:ExprNode[] = [];

    constructor(t:Token | null,elements:ExprNode[]){
        super(t);
        this.elements = elements;
    }

    print(){
        process.stdout.write("[");
        this.elements.forEach((e,i) => {
            if(i > 0){
                process.stdout.write(",")
            }
            e.print();
        })
        process.stdout.write("]")
    }
}

class ListNode extends ExprNode {
    elements:ExprNode[] = [];

    constructor(elements:ExprNode[]){
        super(null);
        this.elements = elements;
    }

    toStringTree(){
        if(this.elements.length == 0){
            return this.toString()
        }
        
        let buf = '';
        this.elements.forEach((t,i)=>{
            if(i > 0){
                buf += " "
            }
            buf += t.toStringTree()
        })
        return buf;
    }
}

class AssignNode extends StatNode {
    id:VarNode;
    value:ExprNode;

    constructor(id:VarNode,token:Token | null,value:ExprNode){
        super(token)
        this.id = id;
        this.value  = value;
    }

    print(){
        this.id.print();
        process.stdout.write("=");
        this.value.print();
        process.stdout.write(" ")
    }
}

class PrintNode extends StatNode {
    value:ExprNode;

    constructor(token:Token | null,value:ExprNode){
        super(token)
        this.value = value;
    }

    print(){
        process.stdout.write("print ");
        this.value.print();
        process.stdout.write("\n")
    }
}

export {
    Token,
    AddNode,
    VectorNode,
    IntNode,
    StatNode,
    VarNode,
    AssignNode,
    ExprNode,
    MultNode,
    PrintNode,
    StatListNode
}